import os
import ahocorasick
import json

'''
Level 1推理引擎
使用Ac自动机对用户输入的问题进行模式串匹配，拿到问题中的关键词，为L2推理引擎做预处理
"先理解用户问的是什么, 同义归并, 如, '鱼'和'鱼类'指代的应该是同一事物"
1.西太平洋有什么鱼 or 哪些鱼类分布在西太平洋
2.红点石斑鱼的特征 or 红点石斑鱼简介
3.红点石斑鱼分布于哪里
4.红点石斑鱼和欧洲䲗分布在哪里
5.红点石斑鱼属于什么类别?(界门纲目科属种)
......
bio_phylum_cn（门），
    bio_class_cn（纲），bio_order_cn（目），bio_family_cn（科）
'''


class L1_engine:
    def __init__(self):
        # L1_Knowledge_base的base_path
        base_path = '../Knowledge_base/L1_Knowledge_base/'
        # L1特征词路径
        self.fish_name_path = os.path.join(base_path, 'fish_name.txt')
        self.fish_name_en_path = os.path.join(base_path, 'fish_name_en.txt')
        self.bio_phylum_cn_path = os.path.join(base_path, 'bio_phylum_cn.txt')
        self.bio_class_cn_path = os.path.join(base_path, 'bio_class_cn.txt')
        self.bio_order_cn_path = os.path.join(base_path, 'bio_order_cn.txt')
        self.bio_family_cn_path = os.path.join(base_path, 'bio_family_cn.txt')
        self.place_path = os.path.join(base_path, 'place.txt')
        # 加载特征词（去除空格）
        self.fish_name_wds = [i.strip() for i in open(self.fish_name_path, encoding='utf-8') if i.strip()]
        self.fish_name_en_wds = [i.strip() for i in open(self.fish_name_en_path, encoding='utf-8') if i.strip()]
        self.bio_phylum_cn_wds = [i.strip() for i in open(self.bio_phylum_cn_path, encoding='utf-8') if i.strip()]
        self.bio_class_cn_wds = [i.strip() for i in open(self.bio_class_cn_path, encoding='utf-8') if i.strip()]
        self.bio_order_cn_wds = [i.strip() for i in open(self.bio_order_cn_path, encoding='utf-8') if i.strip()]
        self.bio_family_cn_wds = [i.strip() for i in open(self.bio_family_cn_path, encoding='utf-8') if i.strip()]
        self.place_wds = [i.strip() for i in open(self.place_path, encoding='utf-8') if i.strip()]
        # 构建特征词表
        self.words_table = list(self.fish_name_wds + self.fish_name_en_wds + self.bio_phylum_cn_wds +
                                self.bio_class_cn_wds + self.bio_order_cn_wds + self.bio_family_cn_wds +
                                self.place_wds)
        # 构造actree
        self.my_actree = self.build_actree(self.words_table)
        # 构造词典
        print('Model Initializing...')
        self.keywords_mapping_dict = self.build_keywords_mapping_dict()
        print('Model load finished...')

    def L1_inference(self, question):
        """
        L1推理引擎, 本类主入口
        :param question:
        :return:
        """
        # 推理数据的字典
        data = {}
        keywords_dict = self.check_keywords(question)
        # # 判空
        # if not keywords_dict:
        #     return {}
        data['args'] = keywords_dict
        # 收集关键字对应的类型
        types = []
        for type in keywords_dict.values():
            types += type
        '''
        问题类型(内容)推理: 通过收集到的关键字和对应的类型
        '''
        questions_types = []
        # rules
        with open('../Knowledge_base/L1_Knowledge_base/rules/L1_rules.json', 'r', encoding='utf-8') as f:
            json_file_str = f.read()
            # loads要求字符串
            rules_dict = json.loads(json_file_str)
        # 推理过程 --> 匹配规则
        '''
            西太平洋 有什么 鱼 or 哪些 鱼类 分布 在 西太平洋
        '''
        if self.match_keywords(rules_dict.get('鱼'), question) and \
                self.match_keywords(rules_dict.get('统计'), question) and ('place_name' in types):
            questions_types.append('鱼类分布')
        '''
            红点石斑鱼的特征 or 红点石斑鱼简介
        '''
        if self.match_keywords(rules_dict.get('介绍'), question) and \
                ('fish_name' in types or 'fish_name_en' in types):
            questions_types.append('简介')
        '''
            红点石斑鱼属于什么门,纲,科?
        '''
        if self.match_keywords(rules_dict.get('属于'), question) and \
                ('fish_name' in types or 'fish_name_en' in types):
            questions_types.append('生物学分类')

        '''
            红点石斑鱼和欧洲䲗分布在哪里
        '''
        if self.match_keywords(rules_dict.get('地域'), question) and \
                ('fish_name' in types or 'fish_name_en' in types):
            questions_types.append('分布')
        # 将推理结果写入字典
        data['questions_types'] = questions_types
        # 返回给L2推理机
        return data

    def build_actree(self, words_table):
        """
        使用词表构建actree
        :param words_table:
        :return:
        """
        actree = ahocorasick.Automaton()
        for index, word in enumerate(words_table):
            actree.add_word(word, (index, word))
        actree.make_automaton()
        return actree

    def check_keywords(self, question):
        """
        检索提取关键字
        :param question:
        :return:
        """
        # 提取问句关键词, 写入到此关键词列表
        keywords = []
        for entry in self.my_actree.iter(question):
            word = entry[1][1]
            keywords.append(word)
        # 规则: 关键词归并, 如"鱼"和"鱼类"是一个意思(此处的归并定义为"包含关系")
        temp_list = []
        for word1 in keywords:
            for word2 in keywords:
                if word1 in word2 and word1 != word2:
                    temp_list.append(word1)
        keywords = [i for i in keywords if i not in temp_list]
        keywords_dict = {i: self.keywords_mapping_dict.get(i) for i in keywords}

        return keywords_dict

    def build_keywords_mapping_dict(self):
        """
        创建关键词与其对应类型的字典
        :return:
        """
        keywords_mapping_dict = dict()
        for word in self.words_table:
            # 因为没有重复的值
            keywords_mapping_dict[word] = []

            if word in self.fish_name_wds:
                keywords_mapping_dict[word].append('fish_name')
            elif word in self.fish_name_en_wds:
                keywords_mapping_dict[word].append('fish_name_en')
            elif word in self.bio_phylum_cn_wds:
                keywords_mapping_dict[word].append('bio_phylum_cn')
            elif word in self.bio_class_cn_wds:
                keywords_mapping_dict[word].append('bio_class_cn')
            elif word in self.bio_order_cn_wds:
                keywords_mapping_dict[word].append('bio_order_cn')
            elif word in self.bio_family_cn_wds:
                keywords_mapping_dict[word].append('bio_family_cn')
            elif word in self.place_wds:
                keywords_mapping_dict[word].append('place_name')
        return keywords_mapping_dict

    def match_keywords(self, words_list, question):
        """
        检查question中的词与words_list的交集, 有交集则返回true
        :param words_list:
        :param question:
        :return:
        """
        for item in words_list:
            if item in question:
                return True
        return False


if __name__ == '__main__':
    engine = L1_engine()
    # engine.L1_inference('红点石斑鱼和欧洲䲗分布在哪里')
    engine.L1_inference('红点石斑鱼简介')
